﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;

/**
 * 仕様書ではコンパイル&リンクのタイミングは実装が自由に決めて良い。
 * この実装ではRender()関数が初めて呼ばれた時に行う。
 * 従ってシェーダーの中で使われているUnifom名/Attribute名がわかるのはその後。
 * ゆえにこのテストは失敗する。
 * */
/**
 * どうしてこうなっているかというと「OpenGLコンテキストフリー･シーンコンストラクション」を標榜しているので
 * この段階ではまだOpenGLドライバーにアクセスできないから。
 * 自分でパースするかOpenGLコンテキストフリーを止めるか...
 * */

namespace MyTestProject {
    
    public class TestShaderProgram {
        [Fact]
        public void TestConstructor () {
            var vertShader = new VertexShader ("shader/dummy.vert");
            var fragShader = new FragmentShader ("shader/dummy.frag");
            var shaderProg = new ShaderProgram (vertShader, fragShader);

            Assert.Equal (vertShader, shaderProg.VertexShader);
            Assert.Equal (fragShader, shaderProg.FragmentShader);
        }

        [Fact (Skip = "未実装")]
        public void TestAttributes () {
            var vertShader = new VertexShader ("shader/dummy.vert");
            var fragShader = new FragmentShader ("shader/dummy.frag");
            var shaderProg = new ShaderProgram (vertShader, fragShader);

            var attrs = shaderProg.Attributes;

            Assert.Equal (3, attrs.Length);
            Assert.Equal ("positions", attrs[0].Name);
            Assert.Equal ("normals", attrs[1].Name);
            Assert.Equal ("colors", attrs[2].Name);
            Assert.Equal (ShaderVariableType.Vec3, attrs[0].Type);
            Assert.Equal (ShaderVariableType.Vec3, attrs[1].Type);
            Assert.Equal (ShaderVariableType.BVec3, attrs[2].Type);
            Assert.Equal (16, attrs[0].ArraySize);
            Assert.Equal (16, attrs[1].ArraySize);
            Assert.Equal (16, attrs[2].ArraySize);
        }

        [Fact (Skip = "未実装")]
        public void TestUniforms () {
            var vertShader = new VertexShader ("shader/dummy.vert");
            var fragShader = new FragmentShader ("shader/dummy.frag");
            var shaderProg = new ShaderProgram (vertShader, fragShader);

            var unifs = shaderProg.Uniforms;

            Assert.Equal (3, unifs.Length);
            Assert.Equal ("ModelViewMatrix", unifs[0].Name);
            Assert.Equal ("ProjectionMatrix", unifs[1].Name);
            Assert.Equal ("ConstantColor", unifs[2].Name);
            Assert.Equal (ShaderVariableType.Mat4, unifs[0].Type);
            Assert.Equal (ShaderVariableType.Mat4, unifs[1].Type);
            Assert.Equal (ShaderVariableType.Int, unifs[2].Type);
            Assert.Equal (0, unifs[0].ArraySize);
            Assert.Equal (0, unifs[1].ArraySize);
            Assert.Equal (0, unifs[2].ArraySize);
        }

        [Fact]
        public void TestReferences () {
            var vertShader = new VertexShader ("shader/dummy.vert");
            var fragShader = new FragmentShader ("shader/dummy.frag");
            var shaderProg = new ShaderProgram (vertShader, fragShader);

            var refs = shaderProg.References;

            Assert.Equal (2, refs.Length);
            Assert.Same (vertShader, refs[0]);
            Assert.Same (fragShader, refs[1]);
        }

        [Fact]
        public void TestDuplicate () {
            var vertShader = new VertexShader ("shader/dummy.vert");
            var fragShader = new FragmentShader ("shader/dummy.frag");
            var shdrProg = new ShaderProgram (vertShader, fragShader);
            shdrProg.UserID = 100;

            var dup = (ShaderProgram)shdrProg.Duplicate ();

            Assert.Equal (shdrProg.VertexShader, dup.VertexShader);
            Assert.Equal (shdrProg.FragmentShader, dup.FragmentShader);
            Assert.Equal (shdrProg.AttributeCount, dup.AttributeCount);
            Assert.Equal (shdrProg.UniformCount, dup.UniformCount);
            Assert.Equal (shdrProg.UserID, dup.UserID);
        }
    }
}
